package com.rem.cloudalibaba.controller;

import com.rem.cloudalibaba.service.sentinel.SentinelFlowService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 流控规则配置
 * 流量控制，其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标，当达到指定的阈值时对流量进行控制，以避免被瞬时的流量高峰冲垮，从而保障应用的高可用性。
 *
 * @author Rem
 * @date 2021-07-20
 */

@RestController
@Slf4j
public class SentinelFlowController {

    @Autowired
    SentinelFlowService sentinelFlowService;

    /*************************qps--流控效果-快速失败************************************/

    /**
     * qps-直接-快速失败
     * 设置QPS单机阈值为2 当每秒请求量大于2的时候开始限流。
     * Blocked by Sentinel (flow limiting)
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/directly/failFast")
    public String flowQpsDirectlyFailFast() {
        return "qps-直接-快速失败";
    }


    /**
     * qps-关联-快速失败 -- 资源1
     * 当该请求关联到flowQpsRelevanceFailFast2，设置qps阈值为2 不断请求/flow/qps/relevance/failFast2 当阈值大于2时 /flow/qps/relevance/failFast1将被限流
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/relevance/failFast1")
    public String flowQpsRelevanceFailFast1() {
        return "qps-关联-快速失败-资源1";
    }

    /**
     * qps-关联-快速失败 -- 关联资源
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/relevance/failFast2")
    public String flowQpsRelevanceFailFast2() {
        return "qps-关联-快速失败-关联资源";
    }

    /**
     * qps-链路-快速失败 --资源Mini
     * 链路流控模式指的是，当从某个接口过来的资源达到限流条件时，开启限流。
     * 它的功能有点类似于针对来源配置项，区别在于：针对来源是针对上级微服务，而链路流控是针对上级接口，也就是说它的粒度更细。 用到注解@SentinelResource
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/link/failFastMini")
    public String flowQpsLinkFailFastMini() {
        String sentinelResource = sentinelFlowService.sentinelQpsResource();
        return sentinelResource + "-资源小程序端";
    }

    /**
     * qps-链路-快速失败 --资源App
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/link/failFastApp")
    public String flowQpsLinkFailFastApp() {
        String sentinelResource = sentinelFlowService.sentinelQpsResource();
        return sentinelResource + "-资源app端";
    }


    /*************************qps--流控效果-Warm Up************************************/


    /**
     * 它从开始阈值到最大QPS阈值会有一个缓冲阶段，一开始的阈值是最大QPS阈值的1/3，然后慢慢增长，直到最大阈值，适用于将突然增大的流量转换为缓步增长的场景。
     * 设置阈值为15,预热时间3s  刚开始请求最大只能请求5次/s 超过会被限流  3s后阈值变成15
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/directly/warmUp")
    public String flowQpsDirectlyWarmUp() {
        return "qps-直接-Warm Up 预热处理";
    }

    /*************************qps--流控效果-排队等待************************************/


    /**
     * 让请求以均匀的速度通过，单机阈值为每秒通过数量，其余的排队等待； 它还会让设置一个超时时间，当请求超过超时间时间还未处理，则会被丢弃。
     * 设置qps为3,超时时间150ms 请求过来最大通过3个/s 超过会等待  等待超过150ms被丢弃 返回 Blocked by Sentinel (flow limiting)
     *
     * @return
     */
    @GetMapping(value = "/flow/qps/directly/lineUp")
    public String flowQpsDirectlylineUp() {
        return "qps-直接-lineUp 排队等待";
    }


    /*************************线程数--流控模式******************************************/


    /**
     * 线程数-直接失败  设置最大线程数为2
     * 用jmeter 1s请求5个线程  再使用浏览器请求接口 被流控
     *
     * @return
     */
    @GetMapping(value = "/flow/thread/directly")
    public String flowThreadDirectly() {
        return "线程数-直接";
    }


    /**
     * 线程数-关联 -- 资源1
     * 设置 资源1 关联资源 资源2 设置线程数阈值为2 用jmeter 1s请求5个线程压资源2 这个时候请求资源1被限流
     *
     * @return
     */
    @GetMapping(value = "/flow/thread/relevance1")
    public String flowThreadrelevance1() {
        return "线程数-关联-资源1";
    }

    /**
     * 线程数-关联 -- 资源2
     *
     * @return
     */
    @GetMapping(value = "/flow/thread/relevance2")
    public String flowThreadrelevance2() {
        return "线程数-关联-资源2";
    }

}
